#include "app_buffer.h"
#include "log.h"
#include "string.h"
#include "stdlib.h"
/**
 * @brief 创建缓冲区
 * @return 缓冲区指针app_buffer_t*
 */
app_buffer_t *app_buffer_init()
{
    // 1.先创建主缓冲区结构体
    app_buffer_t *buffer = (app_buffer_t *)malloc(sizeof(app_buffer_t));

    // 2.创建两个子缓冲区结构体
    for (int i = 0; i < 2; i++)
    {
        buffer->sub_buffer[i] = (sub_app_buffer_t *)malloc(sizeof(sub_app_buffer_t));
        buffer->sub_buffer[i]->data_ptr = (char *)malloc(APP_BUFFER_MAX_SIZE);
        buffer->sub_buffer[i]->total_len = APP_BUFFER_MAX_SIZE;
        buffer->sub_buffer[i]->data_len = 0;
    }

    // 3.设定读写缓冲区下标
    buffer->read_index = 0;
    buffer->write_index = 1;

    // 4.初始化读写锁
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);

    // 5.返回缓冲区指针
    return buffer;
}

/**
 * @brief 向缓冲区中写入数据
 * @param app_buffer_t* 缓冲区指针
 * @return 0:成功, -1:失败
 */
int app_buffer_write(app_buffer_t *app_buffer, char *write_data, int write_data_len)
{
    // 加锁
    pthread_mutex_lock(&app_buffer->read_lock);
    // 1.获取当前负责写入的缓冲区指针
    sub_app_buffer_t *write_sub_buffer = app_buffer->sub_buffer[app_buffer->write_index];

    // 2.写入数据(1.数据长度作为帧头，2.数据内容作为帧体)
    // 2.1.判断数据长度是否超过缓冲区长度
    if (write_data_len + 1 > write_sub_buffer->total_len - write_sub_buffer->data_len)
    {
        log_error("数据长度超过缓冲区长度");
        pthread_mutex_unlock(&app_buffer->read_lock);
        return -1; // 数据长度超过缓冲区长度
    }
    // 2.2.写入数据长度作为帧头
    write_sub_buffer->data_ptr[write_sub_buffer->data_len] = write_data_len;
    // 2.3.写入数据内容作为帧体
    memcpy(write_sub_buffer->data_ptr + write_sub_buffer->data_len + 1, write_data, write_data_len);

    // 3.增加缓冲区数据长度
    write_sub_buffer->data_len += write_data_len + 1;
    // 4.解锁
    pthread_mutex_unlock(&app_buffer->read_lock);

    return 0;
}

/**
 * @brief 切换读写缓冲区
 */
void app_buffer_swap(app_buffer_t *buffer)
{
    // 1.加锁
    pthread_mutex_lock(&buffer->swap_lock);
    // 2.交换读写缓冲区
    buffer->write_index = buffer->write_index == 0 ? 1 : 0;
    buffer->read_index = buffer->read_index == 0 ? 1 : 0;
    // 3.解锁
    pthread_mutex_unlock(&buffer->swap_lock);
}

/**
 * @brief 从缓冲区中读取数据
 * @param app_buffer_t* 缓冲区指针
 * @param char* 读取数据容器
 * @param int 读取数据容器长度
 * @return int 读取成功返回 实际读取长度, 失败返回-1
 */
int app_buffer_read(app_buffer_t *buffer, char *read_data, int read_data_len)
{
    // 此处需要加锁
    pthread_mutex_lock(&buffer->read_lock);
    // 1.获取当前负责读取的缓冲区指针
    sub_app_buffer_t *read_sub_buffer = buffer->sub_buffer[buffer->read_index];

    // 2.判断缓冲区是否有数据
    if (read_sub_buffer->data_len == 0)
    {
        // 2.1如果没有数据要进行缓冲区的切换
        app_buffer_swap(buffer);
        // 2.2再次获取负责读取的缓冲区指针
        read_sub_buffer = buffer->sub_buffer[buffer->read_index];
        // 2.3再次检查缓冲区是否有数据，如果有数据则读取数据，如果没有数据则返回0
        if (read_sub_buffer->data_len == 0)
        {
            log_error("缓冲区没有数据");
            pthread_mutex_unlock(&buffer->read_lock);
            return 0;
        }
    }

    // 3.有数据读取数据
    // 3.1先读取最开始的帧头
    int read_len = read_sub_buffer->data_ptr[0];
    // 3.2比较要读取的数据长度和读取数据容器的长度
    if (read_len > read_data_len)
    {
        log_error("读取数据容器长度不足");
        pthread_mutex_unlock(&buffer->read_lock);
        return -1; // 读取数据长度超过读取数据容器长度
    }

    // 3.3读取数据(1.把数据内容读取放到数据容器中，2.后面的数据覆盖前面的3.调整缓冲区数据长度)
    memcpy(read_data, read_sub_buffer->data_ptr + 1, read_len);
    int rm_size = read_len + 1; // 读取数据长度+帧头长度
    memmove(read_sub_buffer->data_ptr, read_sub_buffer->data_ptr + rm_size, read_sub_buffer->data_len - rm_size);
    read_sub_buffer->data_len -= rm_size;

    // 此处需要解锁
    pthread_mutex_unlock(&buffer->read_lock);

    // 4.返回读取数据长度
    return read_len;
}

/**
 * @brief 销毁缓冲区
 * @param app_buffer_t* 缓冲区指针
 */
void app_buffer_destroy(app_buffer_t *app_buffer)
{
    for (int i = 0; i < 2; i++)
    {
        free(app_buffer->sub_buffer[i]->data_ptr);
        free(app_buffer->sub_buffer[i]);
    }
    pthread_mutex_destroy(&app_buffer->read_lock);
    pthread_mutex_destroy(&app_buffer->swap_lock);
    free(app_buffer);
}